package com.ddw.meedeeuh.shared;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

import com.google.common.base.Joiner;

/**
 * Represents a utilities class for accessing properties files,
 * parsing values and checking constraints
 * @author cmcnicholas
 *
 */
public abstract class PropertiesUtils {

	/**
	 * Gets a properties value as a boolean or throws an exception
	 * @param properties the properties file to access
	 * @param key the key to find
	 * @param defaultValue the default value to return if key is missing and it is allowed
	 * @param allowMissing whether to allow missing keys and return a default value
	 * @return a boolean of the parsed value
	 */
	public static boolean parseBoolean(Properties properties, String key, boolean defaultValue, boolean allowMissing) {
		if(properties == null) {
			throw new IllegalArgumentException("The properties parameter cannot be null");
		}
		if(key == null) {
			throw new IllegalArgumentException("The key parameter cannot be null");
		}

		if(isMissing(properties, key)) {
			if(allowMissing) {
				return defaultValue;
			}
			throw new RuntimeException("Properties file is missing the key: " + key);
		}

		// Attempt to parse a property boolean as either True|true|1 = true, other = false
		final String propertyValue = properties.getProperty(key);
		try {
			return Integer.parseInt(propertyValue) == 1;
		} catch (NumberFormatException e) {
			return Boolean.parseBoolean(properties.getProperty(key));
		}
	}

	/**
	 * Serializes a boolean value for a properties file
	 * @param value the value to serialize
	 * @return a serialized boolean value
	 */
	public static String serializeBoolean(boolean value) {
		return Boolean.toString(value);
	}

	/**
	 * Serializes a string array for a properties file
	 * @param ignoreStrings the value to serialize
	 * @return a serialized string
	 */
	public static String serializeStringArray(String[] array) {
		for(int i = 0, s = array.length; i < s; i++) {
			if(array[i].indexOf(',') != -1) {
				throw new IllegalArgumentException("Cannot serialize array, array value includes comma");
			}
		}
		return Joiner.on(',').join(array);
	}

	/**
	 * Gets a properties value as a string or throws an exception
	 * @param properties the properties file to access
	 * @param key the key to find
	 * @param defaultValue the default value to return if key is missing and it is allowed
	 * @param allowMissing whether to allow missing keys and return a default value
	 * @return a string of the parsed value
	 */
	public static String parseString(Properties properties, String key, String defaultValue, boolean allowMissing) {
		if(properties == null) {
			throw new IllegalArgumentException("The properties parameter cannot be null");
		}
		if(key == null) {
			throw new IllegalArgumentException("The key parameter cannot be null");
		}

		if(isMissing(properties, key)) {
			if(allowMissing) {
				return defaultValue;
			}
			throw new RuntimeException("Properties file is missing the key: " + key);
		}
		return properties.getProperty(key);
	}

	/**
	 * Gets a properties value as a string array or throws an exception, the
	 * values are parsed and seperated by comma
	 * @param properties the properties file to access
	 * @param key the key to find
	 * @param defaultValue the default value to return if key is missing and it is allowed
	 * @param allowMissing whether to allow missing keys and return a default value
	 * @return a string array of the parsed value
	 */
	public static String[] parseStringArray(Properties properties, String key, String[] defaultValue, boolean allowMissing) {
		if(properties == null) {
			throw new IllegalArgumentException("The properties parameter cannot be null");
		}
		if(key == null) {
			throw new IllegalArgumentException("The key parameter cannot be null");
		}

		if(isMissing(properties, key)) {
			if(allowMissing) {
				return defaultValue;
			}
			throw new RuntimeException("Properties file is missing the key: " + key);
		}
		return properties.getProperty(key).split(",");
	}

	/**
	 * Reads a properties object into memory from a properties file
	 * @param propertiesFile the properties file to load
	 * @return a properties instance
	 */
	public static Properties readPropertiesFile(final File propertiesFile) {
		final Properties properties = new Properties();
		FileInputStream in = null;
		try {
			in = new FileInputStream(propertiesFile);
			properties.load(in);
		} catch (IOException e) {
			throw new RuntimeException("There was a problem reading/parsing the properties file", e);
		} finally {
			if(in != null) {
				try {
					in.close();
				} catch (IOException e) {
					throw new RuntimeException("Failed to close the properties file", e);
				}
			}
		}
		return properties;
	}

	/**
	 * Checks if a properties key is missing
	 * @param properties the properties file to check
	 * @param key the key to check
	 * @return a flag indicating whether the key exists
	 */
	private static boolean isMissing(Properties properties, String key) {
		return properties.containsKey(key) == false;
	}

}
